﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using C1.Silverlight;
using ConfigurationManagement;
using Utilities;

namespace WindowsManagement
{
	public class WindowsHost
	{
		private Dictionary<Button, C1Window> _windows;
		private List<C1Window> _windowsOrder;
		private StackPanel _taskbar;
		private const string Minimize = "Minimize";
		private const string Restore = "Restore";

		private readonly Dictionary<C1WindowState, string> _windowStateActionNameDependencies = new Dictionary<C1WindowState, string>()
		                                                	{
		                                                		{
																	C1WindowState.Floating, Restore
		                                                		},
																{
																	C1WindowState.Minimized, Minimize
		                                                		}
		                                                	};
	
		public WindowsHost(StackPanel taskbar)
		{
			_taskbar = taskbar;
			_taskbar.SizeChanged += OnTaskbarSizeChanged;
			_windows = new Dictionary<Button, C1Window>();
			_windowsOrder = new List<C1Window>();
		}

		public void Add(C1Window newWindow)
		{
			AddEventHandlersToWindow(newWindow);
			var button = CreateTaskbarButton(newWindow);
			
			_taskbar.Children.Add(button);
			ReArrangeTaskbarButtons();

			_windows.Add(button, newWindow);
			_windowsOrder.Insert(0, newWindow);
			newWindow.Show();
		}

		private void AddEventHandlersToWindow(C1Window window)
		{
			window.WindowStateChanged += OnWindowStateChanged;
			window.IsActiveChanged += OnWindowIsActiveChanged;
			window.Closed += OnWindowClosed;
		}

		#region Taskbar

		#region TaskbarButtonContextMenu

		private void ContextMenuActionCloseWindow(object sender, SourcedEventArgs e)
		{
			var menuItem = (C1MenuItem) sender;
			var window = GetWindowByContextMenuItem(menuItem);
			if(window != null)
			{
				window.Close();
			}
		}

		private void ContextMenuActionMinimizeWindow(object sender, SourcedEventArgs e)
		{
			var menuItem = (C1MenuItem) sender;
			var window = GetWindowByContextMenuItem(menuItem);
			if(window != null)
			{
				window.WindowState = C1WindowState.Minimized;
			}
		}

		private void ContextMenuActionRestoreWindow(object sender, SourcedEventArgs e)
		{
			var menuItem = (C1MenuItem)sender;
			var window = GetWindowByContextMenuItem(menuItem);
			if (window != null)
			{
				window.WindowState = C1WindowState.Floating;
			}
		}

		private C1Window GetWindowByContextMenuItem(C1MenuItem menuItem)
		{
			if (menuItem.Menu is C1ContextMenu)
			{
				var button = ((C1ContextMenu)menuItem.Menu).PlacementTarget;
				if (button is Button)
				{
					return _windows[(Button)button];
				}
			}
			return null;
		}

		private C1MenuItem CreateMenuItem(string header, string iconPath, EventHandler<SourcedEventArgs> action)
		{
			Image itemIcon = new Image();
			itemIcon.Source = new BitmapImage(new Uri(iconPath, UriKind.RelativeOrAbsolute));
			itemIcon.Margin = new Thickness(5, 0, 0, 0);
			itemIcon.Height = 12;
			itemIcon.Width = 12;

			var menuItem = new C1MenuItem { Icon = itemIcon, Header = header };
			menuItem.Click += action;
			return menuItem;
		}

		private void ContextMenuItemEnable(C1Window window, C1WindowState windowState, bool value)
		{
			var contextMenu = C1ContextMenuService.GetContextMenu(GetButtonOnTaskbarByWindow(window));
			var menuItem = contextMenu.Items.Where(item => (item is C1MenuItem
														   && ((C1MenuItem)item).Header.ToString() ==
														   _windowStateActionNameDependencies[windowState])).FirstOrDefault();
			if (menuItem != null)
				((C1MenuItem)menuItem).IsEnabled = value;
		}

		private C1ContextMenu CreateContextMenuForTaskbarButton()
		{
			var menu = new C1ContextMenu();
			menu.Items.Add(CreateMenuItem(Restore, "../images/restore.png", ContextMenuActionRestoreWindow));
			menu.Items.Add(CreateMenuItem(Minimize, "../images/minimize.png", ContextMenuActionMinimizeWindow));
			menu.Items.Add(new C1Separator());
			menu.Items.Add(CreateMenuItem("Close", "../images/close.png", ContextMenuActionCloseWindow));
			return menu;
		}

		#endregion

		private Button GetButtonOnTaskbarByWindow(C1Window window)
		{
			var buttonWindowPair = _windows.Where(p => p.Value == window);
			if(buttonWindowPair.Count() != 0)
			{
				return buttonWindowPair.First().Key;
			}
			return null;
		}
		
		private Button CreateTaskbarButton(C1Window window)
		{
			var button = new Button
			{
				Content = window.Header,
				Margin = new Thickness(ConfigurationManager.TaskbarButtonsSideMargin, 0, ConfigurationManager.TaskbarButtonsSideMargin, 0),
				Width = ConfigurationManager.TaskbarButtonsWidth,
				Height = ConfigurationManager.TaskbarButtonsHeight
			};
			button.Click += OnTaskBarButtonClick;
			C1ContextMenuService.SetContextMenu(button, CreateContextMenuForTaskbarButton());
			return button;
		}

		private void ReArrangeTaskbarButtons()
		{
			double allButtonsWidth = _taskbar.Children.Sum(b => (b is Button
																? ((Button)b).Width + ((Button)b).Margin.Right + ((Button)b).Margin.Left
																: 0));

			if (allButtonsWidth > _taskbar.ActualWidth)
			{
				var buttonsCount = _taskbar.Children.Count(item => item is Button);
				foreach (var child in _taskbar.Children)
				{
					if (child is Button)
					{
						((Button)child).Width = Math.Floor((_taskbar.ActualWidth - buttonsCount *
																	(((Button)_taskbar.Children[0]).Margin.Right +
																	 ((Button)_taskbar.Children[0]).Margin.Right)) /
																   buttonsCount);
					}
				}
			}
		}

		#endregion

		#region Event handlers

		private void OnWindowIsActiveChanged(object sender, PropertyChangedEventArgs<bool> e)
		{
			var window = (C1Window)sender;

			if (e.NewValue)
			//if window became active
			{
				_windowsOrder.MoveElementToBegin(window);
				GetButtonOnTaskbarByWindow(window).BorderThickness = new Thickness(3);
			}
			else
			{
				var button = GetButtonOnTaskbarByWindow(window);
				if (button != null)
				{
					button.BorderThickness = new Thickness(1);
				}
			}
		}

		private void OnTaskBarButtonClick(object sender, RoutedEventArgs e)
		{
			var window = _windows[(Button)sender];
			if (window.WindowState == C1WindowState.Floating)
			{
				if (_windowsOrder.First() == window)
				{
					window.WindowState = C1WindowState.Minimized;
				}
				else
				{
					window.BringToFront();
				}
			}
			else
			{
				window.WindowState = C1WindowState.Floating;
				_windowsOrder.MoveElementToBegin(window);
			}
		}

		private void OnWindowStateChanged(object sender, PropertyChangedEventArgs<C1WindowState> e)
		{
			var window = (C1Window) sender;
			if (e.NewValue == C1WindowState.Minimized)
			{
				window.Hide();
			}
			else
			{
				window.Show();
			}
			ContextMenuItemEnable((C1Window)sender, e.NewValue, false);
			ContextMenuItemEnable((C1Window)sender, e.OldValue, true);
		}

		void OnTaskbarSizeChanged(object sender, SizeChangedEventArgs e)
		{
			ReArrangeTaskbarButtons();
		}

		private void OnWindowClosed(object sender, EventArgs e)
		{
			var window = (C1Window) sender;
			var taskbarButton = GetButtonOnTaskbarByWindow(window);
			_taskbar.Children.Remove(taskbarButton);
			_windows.Remove(taskbarButton);
			_windowsOrder.Remove(window);
		}

		#endregion
	}
}